\documentclass{article}
%begin{latexonly}
\usepackage[pdftex,unicode,colorlinks,linkcolor=blue]{hyperref}
\usepackage{CJKutf8}
%end{latexonly}
\usepackage{html}


\begin{document}
\latex{\begin{CJK*}{UTF8}{yahei}}

\begin{center}
{\large Semaphore --- 信号量}
\end{center}

信号量是一种特殊用途的整型数常用于多进程编程中。信号量有两个作用，一个是
互斥({\it mutex})，另一个是同步({\it synchronization})。互斥确保多个进程
不能在同时访问临界区，同步则用于对有限资源共享的限制。互斥使用二值信号量，
而同步使用计数信号量。

几个经典的使用信号量解决的问题：

\begin{enumerate}
\item 生产者--消费者问题：一个有限大小的缓冲区，生产者放入而消费者从中取%
  出，要求当缓冲区满时，生产者阻塞，而缓冲区空时消费者阻塞。解决这问题同%
  时用到了互斥和同步。思路是：采用二值信号量进行互斥，即当生产者往缓冲区%
  中加入元素时消费者不得从中取出，反之亦然。互斥的要求从逻辑上来说是必须%
  的，因为不能保证加入元素和取出元素的操作是原子的，操作过程中某方可能被%
  中断而对方被调度，这样将导致混乱。使用缓冲区大小作为计数来创建计数信号%
  量用于同步。示意代码\latex{如图~\ref{sem_pc}~所示}：\footnote{例子抄自~Andy%
    ~Tanenbaum~著作《Operating Systems -- Design and Implementation》，私自%
    将例子中的~down~和~up~改成~p~和~v~是为了纪念~Dijkstra~老人家，伊是荷%
    兰人，在他阐述信号量的的论文中使用~p(passeren)~表示减信号量操作，%
    用~v(vrijgeven)~表示加操作。另外~Andy~是荷兰女婿，应该也算是半个荷兰%
    人;)}
  %begin{latexonly}
  \begin{figure}[tpb]
    \framebox[1.1\width]{
      \parbox[c]{\textwidth} {\small
        \input sem_pc.c.tex
      }
    }
    \caption{sempaphore~解决生产者--消费者问题}\label{sem_pc}
  \end{figure}
  %end{latexonly}
  \begin{htmlonly}
    \begin{verbatim}
#define N	100		/* 缓冲区中槽的总数 */
#define TRUE	1
typedef int	semaphore;	/* 信号量是一类整型数 */
semaphore	mutex = 1;	/* 用于互斥 */
semaphore	empty = N;	/* 空槽数 */
semaphore	full  = 0;	/* 满槽数 */

void
producer (void)
{
    int item;

    while (TRUE) {
	item = produce_item (); /* 产生元素 */
	p (&empty); /* 减少空槽数，如果当前没有空槽，阻塞 */

	p (&mutex); /* 进入临界区 */
	insert_item (item); /* 加入元素 */
	v (&mutex); /* 离开临界区 */

	v (&full); /* 增加满槽数 */
    }
}

void
consumer (void)
{
    int item;

    while (TRUE) {
	p (&full); /* 减少满槽数，如果当天没有满槽，阻塞 */

	p (&mutex); /* 进入临界区 */
	item = remove_item (item); /* 取出元素 */
	v (&mutex); /* 离开临界区 */

	v (&empty); /* 增加空槽数 */
    }
}
   \end{verbatim}\label{sem_pc}
  \end{htmlonly}
\end{enumerate}

\latex{\end{CJK*}}
\end{document}